/* 
 * File:   script.c
 * Author: bjmey
 *
 * Created on September 5, 2007, 9:51 PM
 */

#include <stdio.h>
#include <stdlib.h>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};

#include "memory.h"
#include "rope.h"
#include "script.h"



static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* not used */
       if (nsize == 0) {
         eruta_free(ptr);
         return NULL;
       }
       else
         return eruta_realloc(ptr, nsize);
}

#define SCRIPT_WRAP(self, function, ARGS)  do { if(!self) return NULL;\
  										   function(self, ARGS ) ; return self; } while (0) ; return NULL
#define SCRIPT_WRAP_NA(self, function) do {  if(!self) return NULL;\
  										 function(self) ; return self; } while (0) ; return NULL										 


Lua::Lua(void)
{
    _state = lua_newstate(l_alloc, (void *) "ERUTA Script allocated memory.");
	_owned = true;
	luaL_openlibs(_state);
	/* Allow use of default Lua libraries. Perhaps this needs to be more limited. */
}

Lua::Lua(Luastate state) {
	_state = state;
	_owned = false;
}

Lua::~Lua(void) {
	if(_owned) {
		lua_close(_state);
		_owned = false;
	}
}

int Lua::eval_c(const char * script ) {
	int res = 0;
	luaL_loadstring(_state, script); 
	res = lua_pcall(_state, 0, LUA_MULTRET, 0);
	if(res) {
		printf("Lua error: %d %s\n", res, lua_tostring(_state, 1));
    	lua_remove(_state, 1);
	}
	return res;
}

int Lua::eval_r(Rope script ) {
    return eval_c(script.c_str());
}

int Lua::run(const char *filename) {
	int res = luaL_dofile (_state, filename);
	if(res) {
		printf("Lua error: %d %s\n", res, lua_tostring(_state, 1));
    	lua_remove(_state, 1);
    	return res;
	}
	return res;
}



void Lua::initialise(void)
{
    // _state = 0;
    // _state = lua_open();
   	

    baselibopen();
    tablibopen();
    strlibopen();
    mathlibopen();
    /* 
	     These four standard libraries should be safe for general use. 
	     iolibopen() and oslibopen are NOT safe at this point.
	*/    
}


void Lua::baselibopen(void) {
  // luaL_baselibopen (_state);
}

void Lua::tablibopen(void) {
  // luaL_tablibopen  (_state);
}

void Lua::strlibopen(void) {
   // luaL_strlibopen  (_state);
}

void Lua::mathlibopen(void) {
  // luaL_mathlibopen (_state);
}

void Lua::iolibopen(void) {
  // luaL_iolibopen (_state);
}

void Lua::oslibopen(void)
{
  // luaL_iolibopen (_state);
}



void Lua::getglobal(const char *varname)
  /* Gets the value of a global, and leaves it on the stack.
	DOES NOT WORK ON TABLES!!! */
{
     pushstring(varname);
     gettable(LUA_GLOBALSINDEX);
} 

void Lua::getglobalx(const char *varnamex, const char * assignto)
  /*
     Gets the value of a global, and leaves it on the stack.
     This one works on tables and complex structs,  but also assigns
     the value to a global with the name "assignto" as a side effect,
     to simplify implementation. This might cause trouble when threading
     or such is used.
  */
{
    Rope aid;
    aid = assignto;
    aid += " = ";
    aid += varnamex;
    dostring(aid.c_str());
    getglobal(assignto);
}

#ifdef _NO_WAY
/* These two functions take a globally defined Lua table variable
   name, and extract the table's first-level members into either
   a map of strings or a vector of strings.  Numerical values will
   be converted to strings as well. As a side effect, the table's numerical
   values will be turned into strings. However, this should not cause problems,
   as string-to-number conversion in Lua is transparent.
   In the map, the only the table's string keys are used, whilst
   in the vector, only numerical Lua indexes table are used, and stored in
   the order they have in the lua table.
*/

int Lua::table2map   (Rope tablename, Ropemap & map   )
{
    Rope key, value;
    getglobal(tablename.c_str());
    if(!istable(-1)) { pop(1); return false; }
    // Check the type of the table that is now possibly at index -1
    /* table is in the stack at index `t' */
    pushnil();  /* first key */

    while ( next(-2) != 0) 
    {         
      /* `key' is at index -2 and `value' at index -1 */
      if( !isstring(-2) ) { pop(1); continue; } 
      if( (!isstring(-1)) && (!isnumber(-1)) )
      { pop(1); continue; } 
      /* Skip non-string keys, and non-string or non number values. */
      value = tostring(-1);
      key   = tostring(-2);
      Ropemap::value_type apair(key,value);
      map.insert(apair);       
      pop(1);  
      /* removes `value'; keeps `key' for next iteration */
    }

    return true;
}

int Lua::table2vector(Rope tablename, Ropevector & vec)
{
    int key, bigkey; Rope value;
    getglobal(tablename.c_str());
    if(!istable(-1)) { pop(1); return false; } 
    // Check the type of the table that is now possibly at index -1
    /* table is in the stack at index `t' */
    pushnil();  /* first key */
    bigkey = vec.size();

    while ( next(-2) != 0) 
    {         
      /* `key' is at index -2 and `value' at index -1 */
      if( !isnumber(-2) ) { pop(1); continue; } 
      if( (!isstring(-1)) && (!isnumber(-1)) ) 
      { pop(1); continue; }
      /* Skip non-number keys, and non-string or non number values. 
		  Leave the key on thestack, but get rid of the value. 
	      */
      value = tostring(-1);
      /* We don't accept negative keys, for now. */       
      vec.push_back(value);
      /* XXX Does this preserve the table's order and index values. 
		I doubt it. But do we need them? */             
      pop(1);  
      /* removes `value'; keeps `key' for next iteration */
    }

    return true;
}

#endif

